package com.ikas.ai.server.aop;

import com.ikas.ai.server.error.BusinessException;
import com.ikas.ai.utils.DateTimeUtil;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

@SuppressWarnings("all")
@Component
@Aspect
public class ColumnNameCheckAop {

    /**
     * 定义切入点
     */
    @Pointcut("execution(* pageQuery*(..))")
    public void checkParam() {
        // 切入点为所有pageQuery开头的方法
    }

    /**
     * 检查参数是否为空
     */
    @Around("checkParam()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = ((MethodSignature) pjp.getSignature());
        //得到拦截的方法
        Method method = signature.getMethod();
        //获取方法参数注解，返回二维数组是因为某些参数可能存在多个注解
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        if (parameterAnnotations == null || parameterAnnotations.length == 0) {
            return pjp.proceed();
        }
        //获取方法参数名
        String[] paramNames = signature.getParameterNames();
        //获取参数值
        Object[] paramValues = pjp.getArgs();

        if (paramNames != null) {
            for (int i = 0; i < parameterAnnotations.length; i++) {
                //校验 pageSize pageNum sortOrder
                String paramName = paramNames[i];
                Object paramValue = paramValues[i];
                checkParam(paramName, paramValue);
                for (int j = 0; j < parameterAnnotations[i].length; j++) {
                    if (!(parameterAnnotations[i][j] instanceof ColumnCheck)) {
                        continue;
                    }
                    ColumnCheck columnCheck = (ColumnCheck) parameterAnnotations[i][j];
                    String colNameRange = columnCheck.value();
                    String curSortColumnName = (String) paramValue;
                    // 校验排序列columnName
                    if (StringUtils.isNotBlank(colNameRange) && StringUtils.isNotBlank(curSortColumnName)) {
                        isContainsTargetStr(colNameRange, curSortColumnName);
                    }
                }
            }
        }

        return pjp.proceed(paramValues);
    }

    private void checkPageInfo(String paramName, Object paramValue) throws Exception {
        if (paramName.equals("sortOrder")) {
            checkSortOrder(paramName, paramValue);
        } else if (paramName.equals("pageSize")) {
            checkPageSize(paramValue);
        } else if (paramName.equals("pageNo")) {
            checkPageNum(paramValue);
        }
    }

    private void checkTimePara(String paramName, Object paramValue) {
        if (paramValue == null) {
            return;
        }
        if (paramName.equals("startTime")) {
            String startTime = paramValue.toString();
            if (!startTime.isEmpty() && !(DateTimeUtil.isValidDate(startTime, DateTimeUtil.DATETIMEFORMATTPL) || DateTimeUtil.isValidDate(startTime, DateTimeUtil.DATEFORMATTPL))) {
                throw new BusinessException("时间格式不对");
            }
        }
        if (paramName.equals("endTime")) {
            String endTime = paramValue.toString();
            if (!endTime.isEmpty() && !(DateTimeUtil.isValidDate(endTime, DateTimeUtil.DATETIMEFORMATTPL) || DateTimeUtil.isValidDate(endTime, DateTimeUtil.DATEFORMATTPL))) {
                throw new BusinessException("时间格式不对");
            }
        }
    }

    private void checkParam(String paramName, Object paramValue) throws Exception {
        checkPageInfo(paramName, paramValue);
        checkTimePara(paramName, paramValue);
    }

    /**
     * pageNum大于1
     *
     * @param pageNum
     */
    private void checkPageNum(Object pageNum) throws Exception {
        if (pageNum == null) {
            return;
        }
        int size = (int) pageNum;
        if (size <= 0) {
            throw new Exception("PageNum参数必须是大于等于1的整数");
        }
    }

    /**
     * pageSize不要超过100
     *
     * @param pageSize
     */
    private void checkPageSize(Object pageSize) throws Exception {
        if (pageSize == null) {
            return;
        }
        // controller已经映射成Integer类型，此处不必重复判断
        int size = (int) pageSize;
        if (size > 100 || size <= 0) {
            throw new Exception("PageSize参数必须是100以内的正整数");
        }
    }

    /**
     * sortOrder只能有asc后者desc两种情况
     *
     * @param sortClumnName
     * @param sortOrder
     */
    private void checkSortOrder(String sortClumnName, Object sortOrder) throws Exception {
        if (null != sortOrder) {
            if (StringUtils.isBlank(sortOrder.toString())) {
                return;
            }
            String orderStr = (((String) sortOrder).toUpperCase()).trim();
            if (!"ASC".equals(orderStr) && !"DESC".equals(orderStr)) {
                throw new Exception(String.format("排序参数[%s]无效，必须为ASC或DESC", orderStr));
            }
        }
    }

    /**
     * 判断参数target 是够包含在提供的columnNames中
     *
     * @param columnNames
     * @param target
     */
    private void isContainsTargetStr(String columnNames, String target) throws Exception {
        String[] columnNameArr = columnNames.split(",");
        Set<String> columnNameSet = new HashSet<>(columnNameArr.length);
        Collections.addAll(columnNameSet, columnNameArr);
        if (!columnNameSet.contains(target)) {
            throw new Exception(String.format("排序列名[%s]无效", target));
        }
    }
}
